#include "contourLap.h"
#include <QPainter>
#include <QPointF>
#include <QPolygonF>
#include <QColor>
#include <QFont>
#include <QPen>
#include <QBrush>
#include <QFile>
#include <QTextStream>
#include <QDebug>
#include <QMessageBox>
#include <QWheelEvent>
#include <QMouseEvent>
#include <algorithm>
#include <QPainterPath>
#include <QVector>
#include <cmath>

contourLap::contourLap(QWidget *parent)
    : QMainWindow(parent),
      isDragging(false),
      scaleFactor(1.0),
      viewOffset(0, 0)
{
    ui.setupUi(this);
    
    // 设置plotWidget为透明背景，并允许接收鼠标事件
    ui.plotWidget->setAttribute(Qt::WA_OpaquePaintEvent, false);
    ui.plotWidget->setAttribute(Qt::WA_NoSystemBackground, true);
    ui.plotWidget->installEventFilter(this);
    
    setupPlot();
}

contourLap::~contourLap()
{}

void contourLap::setupPlot()
{
    // 从文件读取井轨迹数据
    if (!loadWellTrajectory()) {
        QMessageBox::warning(this, "警告", "无法读取井轨迹文件！");
    }
    
    // 从文件读取多边形数据
    loadPolygons();
    
    // 计算合适的初始缩放和平移
    double minX = 0, minY = 0, maxX = 0, maxY = 0;
    bool hasData = false;
    
    // 计算井轨迹的边界
    if (!wellTrajectoryPoints.isEmpty()) {
        minX = maxX = wellTrajectoryPoints[0].x();
        minY = maxY = wellTrajectoryPoints[0].y();
        hasData = true;
        
        for (const auto &point : wellTrajectoryPoints) {
            minX = qMin(minX, point.x());
            maxX = qMax(maxX, point.x());
            minY = qMin(minY, point.y());
            maxY = qMax(maxY, point.y());
        }
    }
    
    // 计算多边形的边界
    for (const auto &polygon : polygons) {
        for (const auto &point : polygon) {
            if (!hasData) {
                minX = maxX = point.x();
                minY = maxY = point.y();
                hasData = true;
            } else {
                minX = qMin(minX, point.x());
                maxX = qMax(maxX, point.x());
                minY = qMin(minY, point.y());
                maxY = qMax(maxY, point.y());
            }
        }
    }
    
    // 设置初始视图
    if (hasData) {
        double margin = 100; // 边距
        double viewWidth = ui.plotWidget->width() - 100; // 减去坐标轴宽度
        double viewHeight = ui.plotWidget->height() - 100; // 减去坐标轴高度
        
        double dataWidth = maxX - minX + 2 * margin;
        double dataHeight = maxY - minY + 2 * margin;
        
        // 计算缩放因子
        scaleFactor = qMin(viewWidth / dataWidth, viewHeight / dataHeight);
        
        // 计算偏移量，使数据居中
        double centerX = (minX + maxX) / 2;
        double centerY = (minY + maxY) / 2;
        double screenCenterX = ui.plotWidget->width() / 2;
        double screenCenterY = ui.plotWidget->height() / 2;
        
        viewOffset.setX(screenCenterX - centerX * scaleFactor);
        viewOffset.setY(screenCenterY + centerY * scaleFactor); // Y轴反转
    }
    
    // 启用绘图更新
    ui.plotWidget->update();
}

bool contourLap::loadWellTrajectory()
{
    QFile file("well.txt");
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        return false;
    }
    
    QTextStream in(&file);
    wellTrajectoryPoints.clear();
    
    // 读取文件中的每一行
    while (!in.atEnd()) {
        QString line = in.readLine().trimmed();
        if (line.isEmpty()) continue;
        
        // 分割数据
        QStringList parts = line.split(QRegExp("\\s+"), QString::SkipEmptyParts);
        if (parts.size() >= 2) {
            bool xOk, yOk;
            double x = parts[0].toDouble(&xOk);
            double y = parts[1].toDouble(&yOk);
            
            if (xOk && yOk) {
                wellTrajectoryPoints.append(QPointF(x, y));
            }
        }
    }
    
    file.close();
    
    if (wellTrajectoryPoints.isEmpty()) {
        qDebug() << "井轨迹文件中没有有效数据";
        return false;
    }
    
    return true;
}

void contourLap::loadPolygons()
{
    // 定义多边形文件列表和对应的颜色
    QVector<QPair<QString, QColor>> polygonFiles = {
        {"c1.crv", QColor(0, 0, 255, 100)},    // 蓝色，半透明
        {"c2.crv", QColor(0, 255, 0, 100)},    // 绿色，半透明
        {"c3.crv", QColor(255, 255, 0, 100)}   // 黄色，半透明
    };
    
    polygons.clear();
    polygonColors.clear();
    
    for (const auto &fileInfo : polygonFiles) {
        const QString &filename = fileInfo.first;
        const QColor &color = fileInfo.second;
        
        QFile file(filename);
        if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
            continue;
        }
        
        QTextStream in(&file);
        QPolygonF polygon;
        
        // 读取第一行作为点数
        QString firstLine = in.readLine().trimmed();
        int pointCount = firstLine.toInt();
        
        // 读取点数据
        int readCount = 0;
        while (!in.atEnd() && readCount < pointCount) {
            QString line = in.readLine().trimmed();
            if (line.isEmpty()) continue;
            
            QStringList parts = line.split(QRegExp("\\s+"), QString::SkipEmptyParts);
            if (parts.size() >= 2) {
                bool xOk, yOk;
                double x = parts[0].toDouble(&xOk);
                double y = parts[1].toDouble(&yOk);
                
                if (xOk && yOk) {
                    polygon.append(QPointF(x, y));
                    readCount++;
                }
            }
        }
        
        file.close();
        
        if (polygon.size() >= 3) {
            polygons.append(polygon);
            polygonColors.append(color);
        }
    }
}

void contourLap::paintEvent(QPaintEvent *event)
{
    QMainWindow::paintEvent(event);
    
    // 绘制plotWidget中的内容
    QPainter painter(ui.plotWidget);
    painter.setRenderHint(QPainter::Antialiasing, true);
    
    // 填充背景
    painter.fillRect(ui.plotWidget->rect(), Qt::white);
    
    // 绘制网格
    drawGrid(painter);
    
    // 绘制多边形区域
    drawPolygons(painter);
    
    // 绘制井轨迹线
    drawWellTrajectory(painter);
    
    // 绘制指北针
    drawCompass(painter);
}

void contourLap::mousePressEvent(QMouseEvent *event)
{
    if (ui.plotWidget->rect().contains(event->pos())) {
        lastMousePos = event->pos();
        isDragging = true;
        ui.plotWidget->setCursor(Qt::ClosedHandCursor);
    }
}

void contourLap::mouseMoveEvent(QMouseEvent *event)
{
    if (isDragging) {
        QPoint delta = event->pos() - lastMousePos;
        viewOffset += delta;
        lastMousePos = event->pos();
        ui.plotWidget->update();
    }
}

void contourLap::mouseReleaseEvent(QMouseEvent *event)
{
    isDragging = false;
    ui.plotWidget->setCursor(Qt::ArrowCursor);
}

void contourLap::wheelEvent(QWheelEvent *event)
{
    if (ui.plotWidget->rect().contains(event->pos())) {
        double factor = 1.1;
        if (event->delta() < 0) {
            factor = 0.9;
        }
        
        // 获取鼠标在世界坐标中的位置
        QPointF worldPos = screenToWorld(event->pos());
        
        // 更新缩放因子
        scaleFactor *= factor;
        
        // 调整偏移量，使缩放围绕鼠标位置进行
        QPointF newScreenPos = worldToScreen(worldPos);
        viewOffset += event->pos() - newScreenPos;
        
        ui.plotWidget->update();
    }
}

QPointF contourLap::worldToScreen(const QPointF &worldPoint) const
{
    // Y轴反转
    return QPointF(
        viewOffset.x() + worldPoint.x() * scaleFactor,
        viewOffset.y() - worldPoint.y() * scaleFactor
    );
}

QPointF contourLap::screenToWorld(const QPointF &screenPoint) const
{
    // Y轴反转
    return QPointF(
        (screenPoint.x() - viewOffset.x()) / scaleFactor,
        (viewOffset.y() - screenPoint.y()) / scaleFactor
    );
}

void contourLap::drawWellTrajectory(QPainter &painter)
{
    if (wellTrajectoryPoints.size() < 2) return;
    
    // 设置井轨迹线属性（红色，较粗）
    QPen pen(Qt::red);
    pen.setWidth(3);
    painter.setPen(pen);
    
    // 绘制井轨迹线
    QPainterPath path;
    path.moveTo(worldToScreen(wellTrajectoryPoints.first()));
    
    for (int i = 1; i < wellTrajectoryPoints.size(); i++) {
        path.lineTo(worldToScreen(wellTrajectoryPoints[i]));
    }
    
    painter.drawPath(path);
}

void contourLap::drawPolygons(QPainter &painter)
{
    for (int i = 0; i < polygons.size(); i++) {
        const QPolygonF &polygon = polygons[i];
        const QColor &color = polygonColors[i];
        
        if (polygon.size() < 3) continue;
        
        // 创建屏幕坐标的多边形
        QPolygonF screenPolygon;
        for (const auto &point : polygon) {
            screenPolygon.append(worldToScreen(point));
        }
        
        // 设置多边形属性 - 边框改为黑色并加粗
        QPen pen(Qt::black); // 使用黑色边框
        pen.setWidth(2);     // 加粗边框
        painter.setPen(pen);
        painter.setBrush(QBrush(color));
        
        // 绘制多边形
        painter.drawPolygon(screenPolygon);
        
        // 为等值线添加label
        if (!screenPolygon.isEmpty()) {
            // 获取多边形的中心点
            QPointF center = screenPolygon.boundingRect().center();
            
            // 设置文本样式
            painter.setPen(QPen(Qt::black, 1));
            painter.setFont(QFont("Arial", 10, QFont::Bold));
            
            // 根据多边形索引设置label文本
            QString label;
            if (i == 0) label = "c1";
            else if (i == 1) label = "c2";
            else if (i == 2) label = "c3";
            
            // 绘制文本
            painter.drawText(center, label);
        }
    }
}

double contourLap::calculateWellTrajectoryAngle()
{
    if (wellTrajectoryPoints.size() < 2) {
        return 0.0; // 默认角度
    }
    
    // 使用最小二乘法计算井轨迹的主要方向
    int n = wellTrajectoryPoints.size();
    double sumX = 0, sumY = 0, sumXY = 0, sumXX = 0;
    
    for (const auto &point : wellTrajectoryPoints) {
        sumX += point.x();
        sumY += point.y();
        sumXY += point.x() * point.y();
        sumXX += point.x() * point.x();
    }
    
    double slope = (n * sumXY - sumX * sumY) / (n * sumXX - sumX * sumX);
    double angle = std::atan(slope) * 180.0 / M_PI;
    
    return angle;
}


// 计算井轨迹的中心
QPointF contourLap::calculateWellTrajectoryCenter()
{
    if (wellTrajectoryPoints.isEmpty()) {
        return QPointF(0, 0);
    }
    
    double sumX = 0.0, sumY = 0.0;
    for (const auto &point : wellTrajectoryPoints) {
        sumX += point.x();
        sumY += point.y();
    }
    
    return QPointF(sumX / wellTrajectoryPoints.size(), sumY / wellTrajectoryPoints.size());
}

// 计算井轨迹长度
QPair<double, double> contourLap::calculateWellTrajectoryExtents()
{
    if (wellTrajectoryPoints.size() < 2) {
        return qMakePair(0.0, 0.0);
    }
    
    // 计算井轨迹的角度
    double wellAngle = calculateWellTrajectoryAngle();
    double cosWell = std::cos(wellAngle * M_PI / 180.0);
    double sinWell = std::sin(wellAngle * M_PI / 180.0);
    
    // 计算井轨迹在井轨迹方向上的投影长度
    double minProjection = 0.0, maxProjection = 0.0;
    bool first = true;
    
    for (const auto &point : wellTrajectoryPoints) {
        // 计算点在井轨迹方向上的投影
        double projection = point.x() * cosWell + point.y() * sinWell;
        
        if (first) {
            minProjection = maxProjection = projection;
            first = false;
        } else {
            minProjection = qMin(minProjection, projection);
            maxProjection = qMax(maxProjection, projection);
        }
    }
    
    double length = maxProjection - minProjection;
    return qMakePair(minProjection, maxProjection);
}

// 计算多边形在垂直于井轨迹方向上的宽度范围
QPair<double, double> contourLap::calculateContourWidthExtents()
{
    if (polygons.isEmpty()) {
        return qMakePair(-50.0, 50.0);
    }
    
    // 计算井轨迹的角度
    double wellAngle = calculateWellTrajectoryAngle();
    double cosPerp = std::cos((wellAngle + 90.0) * M_PI / 180.0);
    double sinPerp = std::sin((wellAngle + 90.0) * M_PI / 180.0);
    
    double minProjection = 0.0, maxProjection = 0.0;
    bool first = true;
    
    for (const auto &polygon : polygons) {
        for (const auto &point : polygon) {
            // 计算点在垂直于井轨迹方向上的投影
            double projection = point.x() * cosPerp + point.y() * sinPerp;
            
            if (first) {
                minProjection = maxProjection = projection;
                first = false;
            } else {
                minProjection = qMin(minProjection, projection);
                maxProjection = qMax(maxProjection, projection);
            }
        }
    }
    
    return qMakePair(minProjection, maxProjection);
}

void contourLap::drawGrid(QPainter &painter)
{
    // 设置网格线样式
    QPen pen(Qt::black);
    pen.setStyle(Qt::DotLine);
    painter.setPen(pen);
    
    // 检查数据是否存在
    if (wellTrajectoryPoints.isEmpty() || polygons.isEmpty()) {
        return;
    }
    
    // 计算井轨迹的角度
    double wellAngle = calculateWellTrajectoryAngle();
    
    // 计算井轨迹方向和垂直方向的向量
    double cosWell = std::cos(wellAngle * M_PI / 180.0);
    double sinWell = std::sin(wellAngle * M_PI / 180.0);
    double cosPerp = std::cos((wellAngle + 90.0) * M_PI / 180.0);
    double sinPerp = std::sin((wellAngle + 90.0) * M_PI / 180.0);
    
    // 计算井轨迹在井轨迹方向上的范围
    QPair<double, double> wellExtents = calculateWellTrajectoryExtents();
    double wellMinProj = wellExtents.first;
    double wellMaxProj = wellExtents.second;
    double wellLength = wellMaxProj - wellMinProj;
    
    // 计算井轨迹在垂直于井轨迹方向上的范围
    double wellMinXProj = std::numeric_limits<double>::max();
    double wellMaxXProj = std::numeric_limits<double>::lowest();
    bool first = true;
    for (const auto& point : wellTrajectoryPoints) {
        double xProj = point.x() * cosPerp + point.y() * sinPerp;
        if (first) {
            wellMinXProj = wellMaxXProj = xProj;
            first = false;
        } else {
            wellMinXProj = std::min(wellMinXProj, xProj);
            wellMaxXProj = std::max(wellMaxXProj, xProj);
        }
    }
    double wellXWidth = wellMaxXProj - wellMinXProj;
    
    // 计算多边形在垂直于井轨迹方向上的范围
    QPair<double, double> contourExtents = calculateContourWidthExtents();
    double contourMinProj = contourExtents.first;
    double contourMaxProj = contourExtents.second;
    double contourWidth = contourMaxProj - contourMinProj;
    
    // 设置网格范围：
    // X方向（垂直于井轨迹）：多边形x方向的1.2倍
    // Y方向（沿井轨迹）：井轨迹长度的1.2倍
    double gridWidthX = contourWidth * 1.2;
    double gridWidthY = wellLength * 1.2;
    
    // 计算网格边界，以井轨迹中心为基准
    QPointF wellCenter = calculateWellTrajectoryCenter();
    double wellCenterProjX = wellCenter.x() * cosPerp + wellCenter.y() * sinPerp;
    double wellCenterProjY = wellCenter.x() * cosWell + wellCenter.y() * sinWell;
    
    double gridMinX = wellCenterProjX - gridWidthX / 2.0;
    double gridMaxX = wellCenterProjX + gridWidthX / 2.0;
    double gridMinY = wellCenterProjY - gridWidthY / 2.0;
    double gridMaxY = wellCenterProjY + gridWidthY / 2.0;
    
    // 网格间距
    double gridSpacing = 50.0;
    
    // 调整网格边界到50米整数倍，确保网格闭合
    // 向下取整最小值，向上取整最大值，确保覆盖范围更大
    gridMinX = std::floor(gridMinX / gridSpacing) * gridSpacing;
    gridMaxX = std::ceil(gridMaxX / gridSpacing) * gridSpacing;
    gridMinY = std::floor(gridMinY / gridSpacing) * gridSpacing;
    gridMaxY = std::ceil(gridMaxY / gridSpacing) * gridSpacing;
    
    // 计算网格线数量
    int xSteps = static_cast<int>((gridMaxX - gridMinX) / gridSpacing);
    int ySteps = static_cast<int>((gridMaxY - gridMinY) / gridSpacing);
    
    // 计算网格线在投影坐标系中的位置
    QVector<double> xGridLines, yGridLines;
    for (int i = 0; i <= xSteps; i++) {
        xGridLines << gridMinX + i * gridSpacing;
    }
    for (int i = 0; i <= ySteps; i++) {
        yGridLines << gridMinY + i * gridSpacing;
    }
    
    // 绘制垂直于井轨迹的网格线（在投影坐标系中是垂直的）
    for (double xProj : xGridLines) {
        // 计算网格线的两个端点
        QPointF startPoint, endPoint;
        
        // 从投影坐标系转换到世界坐标系
        double yProj1 = gridMinY; // 网格下边界
        double yProj2 = gridMaxY; // 网格上边界
        
        double x1 = xProj * cosPerp + yProj1 * cosWell;
        double y1 = xProj * sinPerp + yProj1 * sinWell;
        double x2 = xProj * cosPerp + yProj2 * cosWell;
        double y2 = xProj * sinPerp + yProj2 * sinWell;
        
        startPoint = QPointF(x1, y1);
        endPoint = QPointF(x2, y2);
        
        // 转换为屏幕坐标并绘制
        QPointF screenStart = worldToScreen(startPoint);
        QPointF screenEnd = worldToScreen(endPoint);
        painter.drawLine(screenStart, screenEnd);
    }
    
    // 绘制平行于井轨迹的网格线（在投影坐标系中是水平的）
    for (double yProj : yGridLines) {
        // 计算网格线的两个端点
        QPointF startPoint, endPoint;
        
        // 从投影坐标系转换到世界坐标系
        double xProj1 = gridMinX; // 网格左边界
        double xProj2 = gridMaxX; // 网格右边界
        
        double x1 = xProj1 * cosPerp + yProj * cosWell;
        double y1 = xProj1 * sinPerp + yProj * sinWell;
        double x2 = xProj2 * cosPerp + yProj * cosWell;
        double y2 = xProj2 * sinPerp + yProj * sinWell;
        
        startPoint = QPointF(x1, y1);
        endPoint = QPointF(x2, y2);
        
        // 转换为屏幕坐标并绘制
        QPointF screenStart = worldToScreen(startPoint);
        QPointF screenEnd = worldToScreen(endPoint);
        painter.drawLine(screenStart, screenEnd);
    }
}

void contourLap::drawAxes(QPainter &painter)
{
    // 设置坐标轴属性
    QPen axisPen(Qt::black);
    axisPen.setWidth(2);
    painter.setPen(axisPen);
    
    // 设置字体
    painter.setFont(QFont("Arial", 10));
    
    // 绘制坐标轴
    QRect widgetRect = ui.plotWidget->rect();
    int margin = 40;
    
    // X轴
    painter.drawLine(margin, widgetRect.height() - margin, 
                     widgetRect.width() - margin, widgetRect.height() - margin);
    
    // Y轴
    painter.drawLine(margin, margin, margin, widgetRect.height() - margin);
    
    // 绘制轴标签
    painter.drawText(widgetRect.width() / 2 - 50, widgetRect.height() - 10, "水平距离 (m)");
    
    painter.save();
    painter.translate(20, widgetRect.height() / 2);
    painter.rotate(-90);
    painter.drawText(-50, 0, "垂直深度 (m)");
    painter.restore();
}

void contourLap::drawCompass(QPainter &painter)
{
    // 指北针大小
    int size = 50;
    
    // 指北针位置（左上角，留出边距）
    int margin = 60;
    QPoint center(margin, margin);
    
    // 绘制指北针背景
    painter.setBrush(QBrush(Qt::white, Qt::SolidPattern));
    painter.setPen(QPen(Qt::black, 1));
    painter.drawEllipse(center, size/2 + 5, size/2 + 5);
    
    // 绘制指北针指针
    painter.setPen(QPen(Qt::red, 2));
    painter.drawLine(center.x(), center.y() - size/2, center.x(), center.y() + size/2);
    painter.drawLine(center.x() - size/2, center.y(), center.x() + size/2, center.y());
    
    // 绘制"N"字母
    painter.setFont(QFont("Arial", 12, QFont::Bold));
    painter.drawText(center.x() - 5, center.y() - size/2 - 10, "N");
    painter.drawText(center.x() + size/2 + 10, center.y() + 5, "E");
    painter.drawText(center.x() - 5, center.y() + size/2 + 20, "S");
    painter.drawText(center.x() - size/2 - 20, center.y() + 5, "W");
}

bool contourLap::eventFilter(QObject *watched, QEvent *event)
{
    if (watched == ui.plotWidget) {
        switch (event->type()) {
        case QEvent::MouseButtonPress:
            mousePressEvent(static_cast<QMouseEvent*>(event));
            return true;
        case QEvent::MouseMove:
            mouseMoveEvent(static_cast<QMouseEvent*>(event));
            return true;
        case QEvent::MouseButtonRelease:
            mouseReleaseEvent(static_cast<QMouseEvent*>(event));
            return true;
        case QEvent::Wheel:
            wheelEvent(static_cast<QWheelEvent*>(event));
            return true;
        case QEvent::Paint:
            paintEvent(static_cast<QPaintEvent*>(event));
            return true;
        default:
            break;
        }
    }
    return QMainWindow::eventFilter(watched, event);
}
